package sprs;

/* 
* Copyright (C) 2012 AT&T Service
* All Rights Reserved.  No use, copying or distribution of this
* work may be made except in accordance with a valid license
* agreement from AT&T Service.  This notice must be
* included on all copies, modifications and derivatives of this
* work.
*
* AT&T SERVICE MAKES NO REPRESENTATIONS OR WARRANTIES
* ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. AT&T  WIRELESS 
* SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 
* USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*  
*/



import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;

/**
* QMUtil: close any object with a 'close' method. It can close a list or varied number of arguments of objects with close method.
*
* @author zw251y
*/

public class QMUtil {

   private static final String CLOSE = "close";
   @SuppressWarnings("unchecked")
   private static Map<Class, Method> methodCacheMap = (Map<Class, Method>) Collections.synchronizedMap(new HashMap<Class, Method>());

   /**
    * Invoke the close method in the object. If no close method in the object
    * it does nothing.
    *
    * @param obj the Object with a 'close' method.
    */
   private static void closeAndStore(List<Exception> list, Object... args) {
       for (Object obj : args) {
           try {
               if (obj == null) {
                   continue;
               }
               if (obj instanceof Connection) {
                   ((Connection) obj).close();
                   continue;
               }
               if (obj instanceof ResultSet) {
                   ((ResultSet) obj).close();
                   continue;
               }
               Method method = methodCacheMap.get(obj.getClass());
               if (method == null) {
                   method = obj.getClass().getMethod(CLOSE, new Class[]{});
                   methodCacheMap.put(obj.getClass(), method);
               }
               method.invoke(obj);
           } catch (Exception ex) {
               if (list != null) {
                   list.add(ex);
               }
           }
       }
   }

   /**
    * Invoke the close method in the object. If no close method in the object
    * it does nothing. Return a list of Exception for logging purpose.
    *
    * @param obj the Object with a 'close' method.
    */
   public static void closeQuietly(Object... args) {
       closeAndStore(null, args);
   }

   /**
    * Invoke the close method in the object. If no close method in the object
    * it does nothing. Return a list of Exception for logging purpose.
    *
    * @param obj the Object with a 'close' method.
    */
   public static List<Exception> close(Object... args) {
       List<Exception> retList = new ArrayList<Exception>();
       closeAndStore(retList, args);
       return retList;
   }

   public static String loadResourceToString(final String path) {
       final InputStream stream =
               Thread
               .currentThread()
               .getContextClassLoader()
               .getResourceAsStream(path);
       try {
           return IOUtils.toString(stream);
       } catch (final IOException e) {
           throw new IllegalStateException(e);
       } finally {
           IOUtils.closeQuietly(stream);
       }
   }

   public static InputStream loadResourceAsStream(final String path) {
       final InputStream stream =
               Thread
               .currentThread()
               .getContextClassLoader()
               .getResourceAsStream(path);
       return stream;
   }

   /**
    * This Connection can spy the sql in log4j (log the sql with parameters
    * values in statements such as preparedstatement).
    *
    * @param con
    * @return
    */
   public static Connection getSpyConnection(Connection con) {
       try {
           Class c = Class.forName("net.sf.log4jdbc.ConnectionSpy");
           if (con.getClass() == c) {
               return con;
           }
           //Spy connection wrapper.
           con = (Connection) c.getDeclaredConstructor(Connection.class).newInstance(con);
           return con;
       } catch (Exception e) {
           return con;
       }
   }

}

